﻿using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using ZhaoYan.enemy;
using Common;

namespace ZhaoYan
{
    static class MonsterAnimation
    {
        public static readonly string Idel = "idel";
        public static readonly string Run = "run";
        public static readonly string Jump = "Tiao";
        public static readonly string Defend = "Fangyu";
        public static readonly string Attack = "attack_quick";
        public static readonly string Hitted = "shoushang";
    }

    internal class Enemy : IUnit
    {
        #region 初始化
        IEnemy _root = null;
        GameObject _gameObject = null;
        Weapon _weapon = null;
        IAvatarHandle _aim;
        int _remainHP = 0;
        int _remainMP = 0;
        int _id;
        Vector3 _initPosition;
        CharacterController _collider;

        /// <summary>
        /// 玩家进入警戒区
        /// </summary>
        public event Action<IAvatarHandle> OnEnterAlertArea = null;

        public event Action<IAvatarHandle> OnLeaveAlertArea = null;

        public event Action<IAvatarHandle> OnEnterAttackArea = null;

        public event Action<IAvatarHandle> OnLeaveAttackArea = null;

        public event AttachHandler OnBeginAttack = null;

        public event AttachHandler OnEndAttack = null;

        private Action<IAvatarHandle> _currentHandler = null;

        GameObject FindName (GameObject go, string name)
        {
            for (int i = 0; i < go.transform.childCount; ++i)
            {
                GameObject tmp = go.transform.GetChild (i).gameObject;
                if (tmp.name == name)
                {
                    return tmp;
                }
                else
                {
                    tmp = FindName (tmp, name);
                    if (tmp != null)
                    {
                        return tmp;
                    }
                }
            }

            return null;
        }

        public bool Initialze (IEnemy ie, Vector3 initPos, int id)
        {
            if (ie == null)
            {
                return false;
            }

            _initPosition = initPos;
            _id = id;

            _root = ie;

            _gameObject = GameObject.Instantiate (Resources.Load (_root.ObjectName)) as GameObject;
            _gameObject.name = "Geblin";
            _collider = _gameObject.GetComponent<CharacterController>();
            _remainHP = ie.MaxHP;
            _remainMP = ie.MaxMP;

            Position = _initPosition;

            AppInterface.AvatarInterface.OnIPlayerLogin += new Action<IAvatarHandle> (AvatarInterface_OnIPlayerLogin);

            Animation animation = _gameObject.animation;
            animation[MonsterAnimation.Idel].wrapMode = WrapMode.Loop;
            animation[MonsterAnimation.Run].wrapMode = WrapMode.Loop;
            animation[MonsterAnimation.Run].speed = _root.NormalSpeed.z * 2;
            //animation[JUMP_ANIMATION].wrapMode = WrapMode.ClampForever;
            //animation[JUMP_ANIMATION].speed = .8f;
            //animation[DEFEND_ANIMATION].wrapMode = WrapMode.ClampForever;

            animation[MonsterAnimation.Attack].wrapMode = WrapMode.ClampForever;

            _gameObject.animation.CrossFade (MonsterAnimation.Idel);

            OnEnterAlertArea += new Action<IAvatarHandle> (Enemy_OnEnterAlertArea);

            OnLeaveAlertArea += new Action<IAvatarHandle> (Enemy_OnLeaveAlertArea);

            OnEnterAttackArea += new Action<IAvatarHandle> (Enemy_OnEnterAttackArea);

            OnLeaveAttackArea += new Action<IAvatarHandle> (Enemy_OnLeaveAttackArea);

            OnBeginAttack += new AttachHandler (Enemy_OnBeginAttack);

            OnEndAttack += new AttachHandler (Enemy_OnEndAttack);

            OnDead += new Action<IUnit, IUnit> (Enemy_OnDead);

            GameObject tmp = FindName (_gameObject, _root.WeaponName);

            _weapon = new Weapon (tmp);

            _weapon.OnHit += new HitHandler (_weapon_OnHit);

            return true;
        }

        void Enemy_OnDead (IUnit arg1, IUnit arg2)
        {
            //throw new NotImplementedException ();
        }

        void TowardAim ()
        {
            if (_aim.Position.z < Position.z)
            {
                CurrentRotation = new Quaternion (0, 180, 0, 0);
            }
            else
            {
                CurrentRotation = new Quaternion (0, 0, 0, 0);
            }
        }

        #endregion

        #region 攻击
        bool testInAttack (IAvatarHandle ip)
        {
            if (/*Math.Abs (ip.CurrentPosition.x - _gameObject.transform.position.x) < _root.AttackDistance.x
                || Math.Abs (ip.CurrentPosition.y - _gameObject.transform.position.y) < _root.AttackDistance.y
                ||*/
                     Math.Abs (ip.Position.z - _gameObject.transform.position.z) < _root.AttackDistance.z)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        int _attackLenth;
        int _attackStartTick = int.MaxValue;

        void _weapon_OnHit (object sender, int[] target, IAttack attack)
        {
            //AppInterface.GUIInterface.ShowScore (AppInterface.AvatarInterface.IOwner.NameTagTransform, UnityEngine.Random.Range (-5, -15));
            AppInterface.AvatarInterface.IOwner.OnBeat ((byte)attack.Id, UnityEngine.Random.Range (-5, -15), false);
        }

        void Enemy_OnBeginAttack (object sender, IAttack attack)
        {
            _weapon.BeginAttack (attack);
            TowardAim ();
            _attackLenth = (int)(_gameObject.animation[MonsterAnimation.Attack].length * 1000);
            _gameObject.animation.CrossFade (MonsterAnimation.Attack);
            _currentHandler = AttackPlayer;
            _attackStartTick = System.Environment.TickCount;
        }

        /// <summary>
        /// 结束攻击状态，进入待机状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="attack"></param>
        void Enemy_OnEndAttack (object sender, IAttack attack)
        {
            _weapon.EndAttack ();
            _gameObject.animation.Stop ();
            _gameObject.animation.CrossFade (MonsterAnimation.Idel);
            _currentHandler = Idle_Attack;
            _attackStartTick = System.Environment.TickCount;
        }

        void Idle_Attack (IAvatarHandle obj)
        {
            if (System.Environment.TickCount - _attackStartTick >= _root.IdleTick)
            {
                _attackStartTick = int.MaxValue;
                if (testInAttack (_aim))
                {
                    OnEnterAttackArea (_aim);
                }
                else
                {
                    OnLeaveAttackArea (_aim);
                }
            }
        }

        void Enemy_OnEnterAttackArea (IAvatarHandle obj)
        {
            IAttack ia = _root.CreateAttack (_gameObject);
            _gameObject.animation.Stop ();
            _currentHandler = null;

            OnBeginAttack (this, ia);
        }

        void Enemy_OnLeaveAttackArea (IAvatarHandle obj)
        {
            if (testInAlert (obj))
            {
                OnEnterAlertArea (obj);
            }
            else
            {
                OnLeaveAlertArea (obj);
            }
        }

        /// <summary>
        /// 开始攻击玩家
        /// </summary>
        /// <param name="ip"></param>
        void AttackPlayer (IAvatarHandle ip)
        {
            if (System.Environment.TickCount - _attackStartTick >= _attackLenth)
            {
                OnEndAttack (this, null);
            }
        }
        #endregion

        #region 警戒
        void AvatarInterface_OnIPlayerLogin (IAvatarHandle iah)
        {
            // Debug.Log ("Find player: " + iah.Name);
            iah.OnPositionChange += new PositionChangeHandler (ip_OnPositionChange);
        }

        void Enemy_OnLeaveAlertArea (IAvatarHandle obj)
        {
            _gameObject.animation.CrossFade (MonsterAnimation.Idel);
            //throw new NotImplementedException ();
        }

        void Enemy_OnEnterAlertArea (IAvatarHandle obj)
        {
            _gameObject.animation.Stop ();
            _gameObject.animation.CrossFade (MonsterAnimation.Run);
            _aim = obj;
            _aim.OnDead += new Action<IUnit, IUnit> (_aim_OnDead);

            _currentHandler = RunToward;
        }

        void _aim_OnDead (IUnit arg1, IUnit arg2)
        {
            this.Hp = (ushort)_root.MaxHP;
            OnLeaveAlertArea (arg1 as IAvatarHandle);
        }

        /// <summary>
        /// 测试是否是警戒范围之内
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="pos"></param>
        /// <returns></returns>
        bool testInAlert (IAvatarHandle ip)
        {
            if (/*Math.Abs (ip.Position.x - _gameObject.transform.position.x) < _root.AlertDistance.x
                || Math.Abs (ip.Position.y - _gameObject.transform.position.y) < _root.AlertDistance.y
                ||*/
                     Math.Abs (ip.Position.z - _gameObject.transform.position.z) < _root.AlertDistance.z)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        void ip_OnPositionChange (IUnit sender, Vector3 newPos)
        {
            IAvatarHandle ip = (IAvatarHandle)sender;

            if (_aim == null)
            {
                // 如果玩家进入怪物警戒范围
                if (testInAlert (ip))
                {
                    OnEnterAlertArea (ip);
                }
            }
        }

        private const float RaycastHitHeight = 100;
        private const float FootHeight = 0;
        private const int TerrainLayer = 1;
        /// <summary>
        /// 怪物跑向玩家
        /// </summary>
        /// <param name="ip"></param>
        void RunToward (IAvatarHandle ip)
        {
            Vector3 expectPosition;

            TowardAim ();

            //if (ip.Position.z < Position.z)
            //{
            //    expectPosition = new Vector3 (ip.Position.x, Position.y + 10, Position.z - _root.NormalSpeed.z);
            //}
            //else
            //{
            //    expectPosition = new Vector3 (ip.Position.x, Position.y + 10, Position.z + _root.NormalSpeed.z);
            //}

            //RaycastHit hit;
            //if (Physics.Raycast (expectPosition, Vector3.down, out hit, RaycastHitHeight, TerrainLayer))
            //{
            //    expectPosition.y = hit.point.y + FootHeight;
            //}
            //else
            //{
            //    expectPosition.y = ip.Position.y;
            //}

            //Position = expectPosition;

            _collider.SimpleMove(_gameObject.transform.TransformDirection(Vector3.forward) * InputManager.DeltaTime);

            if (OnPositionChange != null)
            {
                OnPositionChange (this, Position);
            }

            if (testInAttack (ip))
            {
                OnEnterAttackArea (ip);
            }
        }
        #endregion

        #region 属性
        private Quaternion CurrentRotation
        {
            get
            {
                return _gameObject.transform.rotation;
            }
            set
            {
                _gameObject.transform.rotation = value;
            }
        }
        #endregion
        public void FixUpdate ()
        {
            if (_aim != null)
            {
                if (_currentHandler != null)
                {
                    _currentHandler (_aim);
                }
            }
            else
            {
                // 进行巡逻
            }
        }

        #region IUnit Members

        public ushort Hp
        {
            get { return (ushort)_remainHP; }
            private set
            {
                _remainHP = value;

                if (_remainHP > _root.MaxHP)
                {
                    _remainHP = _root.MaxHP;
                }
                else if (_remainHP < 0)
                {
                    _remainHP = 0;
                    if (this.OnDead != null)
                    {
                        this.OnDead (this, null);
                    }
                }
            }
        }

        public ushort AllHp
        {
            get { return (ushort)_root.MaxHP; }
        }

        public Vector3 Position
        {
            get
            {
                return _gameObject.transform.position;
            }
            set
            {
                _gameObject.transform.position = value;
            }
        }

        public int Id
        {
            get { return _id; }
        }

        public string Name
        {
            get { return _root.ObjectName + "_" + Id.ToString (); }
        }

        public Transform NameTagTransform
        {
            get { throw new NotImplementedException (); }
        }

        public Transform HeadTransform
        {
            get { throw new NotImplementedException (); }
        }

        public Collider Weapon
        {
            get { throw new NotImplementedException (); }
        }

        public Collider Collider
        {
            get { return _collider; }
        }

        public void OnBeat (byte beat, int hp, bool net)
        {
            if (hp < 0)
            {

            }

            Hp += (ushort)hp;

            if (this.OnHpChange != null)
            {
                OnHpChange (this, hp);
            }
        }

        public void DoAction (ushort actionId, bool net)
        {
            throw new NotImplementedException ();
        }

        public event PositionChangeHandler OnPositionChange;

        public event Action<IUnit, int> OnHpChange;

        public event Action<IUnit, IUnit> OnDead;

        #endregion
    }
}
